#include <iostream>
#include <string>
#include <assert.h>
#include <unistd.h>
#include <vector>
#include "task.hpp"
#include<sys/wait.h>
#include<sys/types.h>
using namespace std;
// 通过父进程控制子进程

const int gnum = 3;
Task t;

class EndPoint
{
private:
    static int number;
public:
    pid_t _child_id;
    int _write_fd; // 父进程只关心向那个管道写
    std::string processname;
public:
    EndPoint(int id, int fd) : _child_id(id), _write_fd(fd)
    {
        char namebuffer[64];
        //process:0[pid :fd]
        snprintf(namebuffer,sizeof(namebuffer),"process:%d[%d,%d]",number++,_child_id,_write_fd);//输入到字符串中
        processname=namebuffer;
    }
    std::string name() const
    {
        return processname;

    }
    ~EndPoint()
    {
    }
};
int EndPoint::number=0;
// 子进程执行的方法
void WaitCommand()
{
    while (true)
    {
        int command=0;
        int n = read(0, &command, sizeof(int));//4字节读
        if (n == sizeof(int))
        {
            t.Execute(command);
        }
        else if (n == 0)
        {
            //std::cout<<"父进程让我退出，我的pid："<<getpid()<<std::endl;
            break;
        }
        else
        {
            break;
        }
    }
}
void creatProcess(vector<EndPoint> *end_points)
{
    vector<int> fds;
    for (int i = 0; i < gnum; i++)
    {
        // 1.1创建管道
        int pipefd[2] = {0};
        int n = pipe(pipefd);
        assert(n == 0);
        (void)n;

        // 1.2创建进程
        pid_t id = fork();
        assert(id != -1);
        // 子进程
        if (id == 0)
        {
            //std::cout<<gitpid()<<"子进程关闭父进程对应写段";

            for(auto& fd:fds)
            {
                //std::cout<<fd<<" ";
                close(fd);
            }
            //std::cout<<std::endl;
            // 1.3关闭不需要fd
            close(pipefd[1]);
            // 所有子进程读取“指令”的时候都从标准输入读取
            // 1.3.1输入重定向[dup2()]
            dup2(pipefd[0], 0);
            // 1.3.2子进程开始等待命令
            WaitCommand();

            exit(0);
        }
        // 父进程
        // 1.3关闭不需要fd
        close(pipefd[0]);
        // 1.4将新的子进程id和父进程管道写端构建到对象中
        end_points->push_back(EndPoint(id, pipefd[1]));
        fds.push_back(pipefd[1]);

    }
}
int ShowBoard()
{
    std::cout<<"**************************************"<<std::endl;
    std::cout<<"*****0.打印日志*************************"<<std::endl;
    std::cout<<"*****1.数据库任务************************"<<std::endl;
    std::cout<<"*****2.网络请求任务**********************"<<std::endl;
    std::cout<<"*****3.exit*****"<<std::endl;
    std::cout<<"**************************************"<<std::endl;
    std::cout<<"请选择";
    int command=0;
    std::cin>>command;
    return command;


}

void ctrlProcess(const vector<EndPoint>& end_points)
{
    int num=0;
    int cnt=0;
    while(true)
    {
        //2.1选择任务
        int command=0;
        command=ShowBoard();
        if(command==3) break;
        if(command<0||command>3) continue;
        // if(command==3) break;

        //2.2选择进程
        // int index=rand()%end_points.size();
        int index=cnt++;
        cnt%=end_points.size();
        std::cout<<"选择了进程："<<end_points[index].name()<<"处理任务："<<command<<std::endl;

        //2.3下发任务
        write(end_points[index]._write_fd,&command,sizeof(command));//4字节写
        sleep(1);
    }
}
void waitprocess(const vector<EndPoint>& end_points)
{
    //1.让子进程全部退出----让父进程关闭所有写端fd 子进程read到文件结尾返回0 read到0子进程退出
    for(int end=0;end<end_points.size();end++)
    {
        std::cout<<"父进程让子进程退出，退出id："<<end_points[end]._child_id<<std::endl;
        close(end_points[end]._write_fd);
        //2.子进程退出后父进程需要回收子进程的僵尸状态waitpid（）

        waitpid(end_points[end]._child_id,nullptr,0);
        std::cout<<"父进程回收子进程："<<end_points[end]._child_id<<std::endl;
    }
    sleep(10);
    // // for(int i=0;i<end_points.size();i++)
    // for(const auto& ep:end_points)
    // {
    //     close(ep._write_fd);
    // }
    // std::cout<<"父进程让所有子进程退出"<<std::endl;
    // sleep(10);

    // //2.子进程退出后父进程需要回收子进程的僵尸状态waitpid（）
    // for(const auto& ep:end_points)
    // {
    //     waitpid(ep._child_id,nullptr,0);//nullptr：不获取退出码
    // }
    // std::cout<<"父进程回收了所有子进程"<<std::endl;
    // sleep(10);

}

int main()
{
    // 1.先构建控制结构 父进程write 子进程read
    vector<EndPoint> end_points;
    creatProcess(&end_points);//创建子进程

    //2.父进程控制
    ctrlProcess(end_points);

    //3.处理退出问题
    waitprocess(end_points);
    
    //
    

    return 0;
}